/*
 * @Author: aleimu
 * @Date: 2021-03-22 09:52:18
 * @Description: 异步更新组件异常 https://blog.csdn.net/u010565037/article/details/88716681
 */

import React from 'react';
import ReactDOM from 'react-dom';


//装饰器方式,但是需要引入支持此语法的组件
function inject_unount(target) {
    // 改装componentWillUnmount，销毁的时候记录一下
    let next = target.prototype.componentWillUnmount
    target.prototype.componentWillUnmount = function () {
        if (next) next.call(this, ...arguments);
        this.unmount = true
    }
    // 对setState的改装，setState查看目前是否已经销毁
    let setState = target.prototype.setState
    target.prototype.setState = function () {
        if (this.unmount) return;
        setState.call(this, ...arguments)
    }
}
//组件B
class TestContainer extends React.Component {
    constructor() {
        super()
        this.state = {
            isShow: true
        }
    }

    render() {
        return (
            <div>
                <button onClick={() => this.setState({ isShow: !this.state.isShow })}>组件 B</button>
                {!!this.state.isShow && <Test />}
            </div>
        )
    }
}
//组件A
// @inject_unount
class Test extends React.Component {
    constructor() {
        super()
        this.state = {
            num: 0
        }
    }
    // 显示组件前运行
    componentDidMount = () => {
        this._isMounted = true;
    }
    // 卸载组件前运行
    componentWillUnmount = () => {
        this.setState = (state, callback) => {
            return;
        };
    }
    getNum = () => {
        //模拟异步请求
        this.timer = setTimeout(() => {
            this.setState({ num: Math.random() })
        }, 3000)
    }

    getNumFix = () => {
        //模拟异步请求,修复异常,catch 
        try {
            if (this._isMounted) {
                this.timer = setTimeout(() => {
                    if (this._isMounted) {
                        this.setState({ num: Math.random() })
                    }

                }, 3000)
            }

        } catch (error) {
            // console.log('1111')
        }

    }
    render() {
        return (
            <div>
                <button onClick={this.getNumFix} >组件 A</button>
                {this.state.num}
            </div>
        )
    }
}
// 在本例子中：
//     当我们点击组件A时，会发送一个异步请求，请求成功后会更新num的值。
//     当我们点击组件B时，会控制组件的A的卸载与装载

// Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.

const App = () => {
    return (
        <div>
            <TestContainer />
        </div>
    )
}

// 点击A 组件后,快速点击一次 B 组件,就会触发异常,主要的意思是我们不能在组件销毁后设置state，防止出现内存泄漏的情况
export default App